package org.rcy.framework.security.filter;

import org.rcy.framework.security.encrypt.AES;
import org.rcy.framework.security.authentication.AbstractFormToken;
import org.rcy.framework.security.authentication.PreFormLoginAuthentication;
import org.rcy.framework.security.encrypt.Base64Utils;
import org.rcy.framework.security.encrypt.RSA;
import org.rcy.framework.security.form.PasswordToken;
import org.rcy.framework.security.source.LoginAuthenticationDetailsSource;
import org.rcy.framework.security.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.nio.charset.Charset;

/**
 * @author 吴康桥
 * @Description
 * @date 2022/10/28 15:35
 */


public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
	public static final String ACCOUNT_PARAM = "account";
	public static final String TICKET_PARAM = "ticket";
	public static final String PASSWORD_PARAM = "password";
	public static final String CODE_PARAM = "code";
	public static final String QRCODE_PARAM = "qrcode";
	private static final String key = "rcy123";
	public static final String IS_ENCRYPTED = "encrypted";
	private static final ThreadLocal<String> PRIVATE_SECRET_KEY = new ThreadLocal<>();

	private boolean postOnly = true;
	private PreFormLoginAuthentication preFormLoginAuthentication;

	static {
		try {
			FileInputStream fis = new FileInputStream("private_key.pem");
			String privateKey = IOUtils.readStreamAsString(fis, "utf-8");
			PRIVATE_SECRET_KEY.set(privateKey);
		}catch (Exception e){

		}
	}

	public LoginAuthenticationFilter(String loginUrl) {
		super(new AntPathRequestMatcher(loginUrl, "POST"));
		this.authenticationDetailsSource = new LoginAuthenticationDetailsSource();
	}

	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
		if (this.postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		} else {
			AbstractFormToken authRequest = this.obtainFormToken(request);
			if (this.preFormLoginAuthentication != null) {
				this.preFormLoginAuthentication.preAuthentication(request, response);
			}

			authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
			return this.getAuthenticationManager().authenticate(authRequest);
		}
	}

	protected AbstractFormToken obtainFormToken(HttpServletRequest request) {
		String account = request.getParameter("ticket");
		if (StringUtils.isEmpty(account)) {
			account = request.getParameter("account");
		} else {
			account = AES.decrypt(account,key);
		}

		String password = this.getPassword(request);
		String code = request.getParameter("code");
		//String qrcode = request.getParameter("qrcode");
		if (!StringUtils.isEmpty(code)) {
			this.logger.info("/login 登录时传入验证码, loginpin{}, code is {}。", account, code);
		}

		return (AbstractFormToken) new PasswordToken(account, password);
	}

	private String getPassword(HttpServletRequest request) {
		String encrypted = request.getParameter("encrypted");
		String password = request.getParameter("password");
		if (!StringUtils.isEmpty(encrypted) && "true".equals(encrypted)) {
			try {
				byte[] bytes = Base64Utils.decode(password);
				byte[] rawBytes = RSA.decryptByPrivateKey(bytes, PRIVATE_SECRET_KEY.get());
				return new String(rawBytes);
			} catch (Exception var6) {
				this.logger.info("Decrypt password fail " + var6.getMessage());
				return password;
			}
		} else {
			return password;
		}
	}

	public void setPostOnly(boolean postOnly) {
		this.postOnly = postOnly;
	}

	@Autowired(required = false)
	public void setAuthenticationDetailsSource(AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
		super.setAuthenticationDetailsSource(authenticationDetailsSource);
	}

	public PreFormLoginAuthentication getPreFormLoginAuthentication() {
		return this.preFormLoginAuthentication;
	}

	public void setPreFormLoginAuthentication(PreFormLoginAuthentication preFormLoginAuthentication) {
		this.preFormLoginAuthentication = preFormLoginAuthentication;
	}
}
